package com.itcoon.cloud.framework.utils;

import org.springframework.util.ReflectionUtils;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;

public class CollectionUtil {

    /**
     * 合并对象属性
     *
     * @param targetType 目标对象
     * @param cols       源对象
     * @param separator
     * @param <T>
     * @param <S>
     * @param <R>
     * @return
     */
    public static <T, S, R> S mergeTo(Class<S> targetType, Collection<T> cols, String separator){
        try {
            S s = targetType.newInstance();
            List<PropertyDescriptor> descriptors = ClassUtil.findPropertyDescriptors(targetType).stream().filter(f->!f.getReadMethod().getDeclaringClass().isAssignableFrom(Object.class)).collect(Collectors.toList());
            for (PropertyDescriptor descriptor : descriptors) {
                Class<?> propertyType = descriptor.getPropertyType();
                if (Collection.class.isAssignableFrom(propertyType)) {
                    Method writeMethod = descriptor.getWriteMethod();
                    Collection<?> propertyCols = List.class.isAssignableFrom(propertyType) ? new ArrayList<>() : Set.class.isAssignableFrom(propertyType) ? new HashSet<>() : null;
                    writeMethod.invoke(s, propertyCols);
                }
            }
            descriptors = ClassUtil.findPropertyDescriptors(targetType).stream().filter(f->!f.getReadMethod().getDeclaringClass().isAssignableFrom(Object.class)).collect(Collectors.toList());
            if (!cols.isEmpty()) {
                Iterator<T> iterator = cols.iterator();
                int index = 0;
                while (iterator.hasNext()) {
                    T t = iterator.next();
                    for (PropertyDescriptor descriptor : descriptors) {
                        Class<?> propertyType = descriptor.getPropertyType();
                        Object value = ReflectionUtils.findField(t.getClass(), descriptor.getName()) == null ? SpringReflectionUtils.getField(t, descriptor.getName().substring(0, descriptor.getName().length()-1))  :SpringReflectionUtils.getField(t, descriptor.getName());
                        if (Collection.class.isAssignableFrom(propertyType)) {
                            Collection<R> targetCols = (Collection<R>) descriptor.getReadMethod().invoke(s);
                            if (value instanceof Collection) {
                                Collection<R> vals = (Collection<R>) value;
                                targetCols.addAll(vals);
                            } else if (value instanceof String) {
                                Collection<String> vals = Arrays.asList(((String) value).split(separator));
                                targetCols.addAll((Collection<? extends R>) vals);
                            }else{
                                if(value != null){
                                    targetCols.add((R)value);
                                }
                            }
                        } else {
                            if (index == 0) {
                                descriptor.getWriteMethod().invoke(s, value);
                            }
                        }
                    }
                    index++;
                }
            }
            return s;
        }catch (Exception e){
            throw new RuntimeException(e.getMessage(), e);
        }
    }
}
